package org.loofer.uikit.text;

import android.text.InputFilter;
import android.text.Spanned;

public class LengthFilter implements InputFilter {
    private final LengthCallback mLengthCallback;
    private LengthConverter mLengthConverter;
    private final int mMaxLength;

    public interface LengthCallback {
        void onMaxLengthReached(int i);
    }

    public LengthFilter(int maxLength) {
        this(maxLength, null);
    }

    public LengthFilter(int maxLength, LengthCallback callback) {
        this.mLengthConverter = null;
        this.mMaxLength = maxLength;
        this.mLengthCallback = callback;
    }

    public void setLengthConverter(LengthConverter converter) {
        this.mLengthConverter = converter;
    }

    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
        int destReserveLen;
        int srcLen;
        LengthConverter lengthConverter = this.mLengthConverter;
        if (lengthConverter == null) {
            destReserveLen = dest.length() - (dend - dstart);
        } else {
            destReserveLen = lengthConverter.convert(dest, 0, dstart) + lengthConverter.convert(dest, dend, dest.length());
        }
        if (lengthConverter == null) {
            srcLen = end - start;
        } else {
            srcLen = lengthConverter.convert(source, start, end);
        }
        int keep = this.mMaxLength - destReserveLen;
        if (keep <= 0) {
            notifyMaxLengthReached();
            return "";
        } else if (keep >= srcLen) {
            return null;
        } else {
            notifyMaxLengthReached();
            if (lengthConverter != null) {
                keep = lengthConverter.reverse(source, start, start + keep);
                if (keep <= 0) {
                    return "";
                }
            }
            keep += start;
            if (Character.isHighSurrogate(source.charAt(keep - 1))) {
                keep--;
                if (keep == start) {
                    return "";
                }
            }
            return source.subSequence(start, keep);
        }
    }

    private void notifyMaxLengthReached() {
        if (this.mLengthCallback != null) {
            this.mLengthCallback.onMaxLengthReached(this.mMaxLength);
        }
    }
}
